/*
 * @Author: 王炜皓
 * @Date: 2023-07-29 16:03:18
 * @LastEditTime: 2023-07-29 16:03:30
 * @LastEditors: 王炜皓
 * @Description: 计算风场网格
 * @FilePath: \cesium-tool\src\views\test\extend\effect\wind\CalculateWindyGrids.ts
 */

 
import { HOptions, WindyData } from './WindyTypes';
 
export default class CalculateWindyGrids {
  header: HOptions;
  grid: number[][][];
  vMax: number; // 东西向最大速度分量
  vMin: number; // 东西向最小速度分量
  uMax: number; // 南北向最大速度分量
  uMin: number; // 南北向最小速度分量
  // 可以根据实际应用选择是否还需要计算网格单元的最大和最小风速
 
  /**
   * 根据风场源数据创建风场网格数据
   * @param sourceData 风场源数据
   */
  constructor(sourceData: WindyData) {
    const { header, uComponent, vComponent } = sourceData;
    this.header = header;
    this.grid = [];
    this.vMax = 0;
    this.vMin = 0;
    this.uMax = 0;
    this.uMin = 0;
    this.init(vComponent, uComponent);
  }
 
  /**
   * 初始化风场网格
   * @param vComponent 东西方向 V 的风速数据集
   * @param uComponent 南北方向 U 的风速数据集
   */
  init(vComponent: number[], uComponent: number[]) {
    let k = 0;
    for (let j = 0; j < this.header.ny; j++) {
      let rows: number[][] = [];
      for (let i = 0; i < this.header.nx; i++, k++) {
        // 更新东西向，南北向风向最值
        this.vMax = Math.max(this.vMax, vComponent[k]);
        this.vMin = Math.min(this.vMin, vComponent[k]);
        this.uMax = Math.max(this.uMax, uComponent[k]);
        this.uMin = Math.min(this.uMin, uComponent[k]);
        let uv = this.calculateUV(uComponent[k], vComponent[k]);
        rows.push(uv);
      }
      this.grid.push(rows);
    }
  }
 
  /**
   * 计算单元分量
   * @param u 南北向分量
   * @param v 东西向分量
   * @returns 单元分量值
   */
  calculateUV(u: number, v: number) {
    return [u, v, Math.sqrt(u * u + v * v)];
  }
 
  /**
   * 插值计算（双线性）
   * @returns
   */
  interpolationCal(
    x: number,
    y: number,
    uv_00: number[],
    uv_10: number[],
    uv_01: number[],
    uv_11: number[]
  ) {
    const rx = 1 - x;
    const ry = 1 - y;
    const a = rx * ry;
    const b = x * ry;
    const c = rx * y;
    const d = x * y;
    const u = uv_00[0] * a + uv_10[0] * b + uv_01[0] * c + uv_11[0] * d;
    const v = uv_00[1] * a + uv_10[1] * b + uv_01[1] * c + uv_11[1] * d;
    return this.calculateUV(u, v);
  }
 
  /**
   * 获取风场网格分量值
   * @param x
   * @param y
   * @returns
   */
  getUV(x: number, y: number): number[] {
    // 判断是否在范围内
    if (x < 0 || y < 0 || x >= this.header.nx - 1 || y >= this.header.ny - 1)
      return [0, 0, 0];
 
    const x0 = Math.floor(x);
    const y0 = Math.floor(y);
    if (x0 === x && y0 === y) return this.grid[y][x];
 
    const x1 = x0 + 1;
    const y1 = y0 + 1;
    const uv_00 = this.getUV(x0, y0);
    const uv_10 = this.getUV(x1, y0);
    const uv_01 = this.getUV(x0, y1);
    const uv_11 = this.getUV(x1, y1);
    return this.interpolationCal(x - x0, y - y0, uv_00, uv_10, uv_01, uv_11);
  }
}